"""
класс connSQL - обеспечивает процедуру соединения с сервером
класс fmServer - модальная форма (параметры соединения с сервером)
"""
import os
import sys
import configparser
from PyQt5.QtSql import *
from PyQt5.QtWidgets import *

class connSQL():
    """
Создает соединение с SQL сервером. Параметры соединения читает из файла
конфигурации. Если соедиение не удалось, открывает диалоговое окно для
интерактивной настройки соединения.
Методы: __init__, connect, open
Переменные: Driver, IniFile
    """
    def __init__(self, IniFile="ini.ini", Driver="QMYSQL"):
        """
Читает конфиг файл. Если файл отсутствует, создает параметры соединения по-умолчанию.
Аргументы название конфигурационного файла и имя дракйвера из QtSQL.
        """
        self.Driver = Driver
        self.IniFile = IniFile

        self.path_file = os.getenv('APPDATA') + "\\" + IniFile                      # путь до файла ini
        self.config = configparser.ConfigParser()                                # создаем переменную ini
        if not self.config.read(self.path_file):                                      # если конфиг пуст
            s = """
                [SERVER]
                HostName=
                DatabaseName=
                UserName=
                Password=
                """
            self.config.read_string(s)

    def connect(self):
        """
Открывает соединение с параметрами из конфига. Если соединение не удалось открывает
модальную форму для настройки соединения с сервером. Если соединение удалось, 
записывает конфиг и возвращает указатель на базу данных.
        """
        db = self.open()                                                 # открываем соединение
        if not db:                                                          #
            dialog = fmServer(self.config, self.open)                                       # Создаем экземпляр формы
            result = dialog.exec_()                                         # запускаем модально
            if result == QDialog.Accepted:
                with open(self.path_file, 'w') as configfile:
                    self.config.write(configfile)
                return dialog.db
        else:                                                               # ошибка открытия
            return db                                                       # соединение открыто


    def open(self):
        """
Загружает параметры из переменной конфигурации в переменную базы данных.
Если соединение удалось - возвращает переменную базы данных.
Если не удалось - выводит сообщение об ошибке.
        """
        if QSqlDatabase.contains():                                         # если соединение уже имеется
            db = QSqlDatabase.database()                                    # используем его
        else:
            db = QSqlDatabase.addDatabase(self.Driver)                         # создаём новое соединение

        server = self.config['SERVER']                                           # берём из конфиг секцию SERVER
        db.setHostName(server['HostName'])
        db.setDatabaseName(server['DatabaseName'])
        db.setUserName(server['UserName'])
        db.setPassword(server['Password'])

        if db.open():                                                       # открываем соединение
            return db
        else:
            error = db.lastError()
            num_error = error.number()
            if num_error == 1044:
                message = "Недопустимое имя базы данных. Проверьте правильность в поле [База]."
            elif num_error == 1045:
                message = "Недопустимое имя пользователи и/или пароль. Проверьте правильность в полях [Логин] и [Пароль]"
            elif num_error == 2003:
                message = "Сервер не отвечает на запросы. Проверьте правильность IP адреса в поле [Сервер]."
            else:
                message = ("код ошибки: {}. Оригинальное сообщение: {} "
                    .format(num_error,error.text()))
            dialog = QMessageBox()
            dialog.setIcon(QMessageBox.Warning) # иконка
            dialog.setWindowTitle("СООБЩЕНИЯ СЕРВЕРА")
            dialog.setText(message)
            dialog.exec_()
        


        
class fmServer(QDialog):
    """
Строки документации класса обобщают его поведение и перечисляют открытые 
методы и переменные экземпляра. Если класс предназначен для подклассов, и 
имеет дополнительный интерфейс для подклассов, этот интерфейс должен быть 
указан отдельно (в строке документации). Конструктор класса должны быть 
задокументирован в документации метода __init__. Отдельные методы должны 
иметь свои строки документации.
"""

    def __init__(self, config, open):
        """
Создание диалогового окна типа форма.
        """
        super().__init__()                                              # запускаем init родительского класса
        self.config = config
        self.open = open
        server = self.config['SERVER']                                  # берём из конфиг секцию SERVER
        self.edtHostName = QLineEdit(server['HostName'])                # текстовые поля формы
        self.edtDatabaseName = QLineEdit(server['DatabaseName'])
        self.edtUserName = QLineEdit(server['UserName'])
        self.edtPassword = QLineEdit(server['Password'])

        self.btnConnected = QPushButton('ПРОВЕРКА СОЕДИНЕНИЯ')          # кнопка
        self.btnConnected.clicked.connect(self.btnConnectedClick)

        self.form = QFormLayout()                                       # контейнер форма
        self.form.addRow("Сервер", self.edtHostName)
        self.form.addRow("База", self.edtDatabaseName)
        self.form.addRow("Логин", self.edtUserName)
        self.form.addRow("Пароль", self.edtPassword)
        self.form.addRow(self.btnConnected)
        self.setLayout(self.form)
        self.setWindowTitle("ПАРАМЕТРЫ СОЕДИНЕНИЯ")
        self.setMinimumWidth(200)


    def btnConnectedClick(self):
        """
Проверка заполнения полей. Загрузка значений полей в переменную конфигурации.
Попытка соединения с сервером. Закрытие формы в случае удачного соединения

        """
        if (not self.edtHostName.text() or                              # проверка заполнения полей
            not self.edtDatabaseName.text() or
            not self.edtUserName.text() or
            not self.edtPassword.text()):
            dialog = QMessageBox()
            dialog.setIcon(QMessageBox.Warning) # иконка
            dialog.setWindowTitle("ПРЕДУПРЕЖДЕНИЕ")
            dialog.setText("Все поля в этой форме обязательны для заполнения.")
            dialog.exec_()
            return

        server = self.config['SERVER']                                  # берём из конфиг секцию SERVER
        server['HostName'] = self.edtHostName.text()                    # загрузка полей в
        server['DatabaseName'] = self.edtDatabaseName.text()
        server['UserName'] = self.edtUserName.text()
        server['Password'] = self.edtPassword.text()

        self.db = self.open()                                   # открываем соединение
        if self.db:                                                     #
            self.accept()

            


if __name__ == '__main__':
    app = QApplication(sys.argv)
    D = connSQL("test.ini")
    db = D.connect()
    if db:
        print("OK")
